<template>
  <!-- 数据库预览 -->
  <div id="data-preview-table" class="database-data-preview-card">
    <!-- 多表tabs -->
    <a-tabs v-model="activeTable" type="card" @change="changeTablePreviewData">
      <a-tab-pane v-for="table in selectedTables" :key="table" :tab="table">
        <dataset-preview-table
          v-show="loadSuccessed"
          :head="selectedTableData ? selectedTableData.head : []"
          :data="selectedTableData ? selectedTableData.data : []"
          :data-type="'database'"
          @change-semantic="onChangeSemantic"
        />
        <p v-show="!loadSuccessed" class="load-error-msg">
          数据加载失败，<span class="reload" @click="reloadData">请重试</span>
        </p>
      </a-tab-pane>
    </a-tabs>
  </div>
</template>

<script lang="ts">
/**
 * 数据库数据预览
 * @author Jinhui Hou
 */
import { Component, Prop, Vue, Watch } from 'vue-property-decorator'
import DatasetPreviewTable from '@/components/data/DatasetPreviewTable.vue'
import DataUploadStore from '@/store/modules/data-upload'
import { getTablesHead } from '@/api/data'
import { cloneDeep } from 'lodash'
import { initDesensitizationList } from '@/components/data/utils/init-desensitization'
import UserGuideStore from '@/store/modules/user-guide'

@Component({
  components: {
    DatasetPreviewTable,
  },
})
export default class DatabaseDataPreview extends Vue {
  @Prop({ type: String, default: 'table' }) selectedDataType!: string // 数据类型

  private selectedPreviewTableName: string = '' // 选中的预览数据表的表名
  public isSetDesensitization: boolean = false
  // 激活项
  public activeTable: string = ''
  // 加载状态
  private loadSuccessed: boolean = false

  // 选择的数据库表
  public get selectedTables() {
    return DataUploadStore.selectedTables
  }
  // 数据库表预览数据 ( head: head 包含表头,类型,语义信息;data: 数据内容)
  public get selectedTableData() {
    return DataUploadStore.selectedTableData
  }
  // 脱敏配置
  public get haveSetDesensitization() {
    return DataUploadStore.haveSetDesensitization
  }
  // 数据库导入时记录的语义，按照表名进行划分  推断语义（数据库没有数据类型推断）
  public get databaseHeadSemantic() {
    return DataUploadStore.databaseHeadSemantic
  }

  public mounted() {
    DataUploadStore.setIsDataSemanticInfer(false) // 默认不使用语义推荐
  }

  /**
   * 表单中的选择的数据库表发生变化
   * @param tables
   */
  @Watch('selectedTables', { deep: true, immediate: true })
  public selectedTablesChange(tables: any[]) {
    this.updateTables(tables, 'select')
  }

  /**
   * 外部数据库 获取数据表的表头， 用来初始化 脱敏配置项， 数据类型、语义推荐
   * @author Jinhui Hou
   */
  public async getTablesHead(tableNames: any) {
    const parameters = {
      ...DataUploadStore.databaseConfig,
      tableNames,
    }
    const response: any = await getTablesHead({ data: parameters })
    if (response.data.code === 100) {
      this.initDesensitizationList(response.data.result)
      this.initDatabaseSemantic(response.data.result)
    }
  }

  /**
   * 初始化 脱敏列表
   * @param tables
   */
  public initDesensitizationList(tables: any) {
    // 历史脱敏配置的备份, 用户已经配置过的脱敏配置， 在增加导入数据表的时候能够保留
    const historyDesensitization: any = cloneDeep(
      DataUploadStore.haveSetDesensitization
    )
    DataUploadStore.setHaveSetDesensitization({}) // init
    if (tables) {
      const tableDesensitizationMap: any = initDesensitizationList(
        tables,
        historyDesensitization
      )
      DataUploadStore.setHaveSetDesensitization(tableDesensitizationMap)
    } else {
      DataUploadStore.setHaveSetDesensitization({})
    }
  }

  /**
   * 初始化数据库导入时的语义初始信息
   */
  public initDatabaseSemantic(tableHeadInfo: any[]) {
    const databaseHeadSemantic: any = {}
    tableHeadInfo.forEach((data: { tableName: string; head: any[] }) => {
      databaseHeadSemantic[data.tableName] = {}
      data.head.forEach((column: any) => {
        databaseHeadSemantic[data.tableName][column.name] = {
          recommendSemantic: column.recommendSemantic,
          type: column.type,
        }
      })
      if (data.tableName === this.selectedTableData.name) {
        // 给selectedTableData中塞语义
        const { head } = this.selectedTableData
        head.forEach((column: any) => {
          column.recommendSemantic = data.head.filter(
            (c) => c.name === column.name
          )[0].recommendSemantic
        })
        DataUploadStore.setSelectedTableData({
          ...this.selectedTableData,
          head,
        })
      }
    })
    DataUploadStore.setDatabaseHeadSemantic(databaseHeadSemantic)
  }

  /**
   * 脱敏设置更新确认后
   */
  public importAndDesensitizationTriggeringEvent() {
    // 数据库 （修改了脱敏配置）， 更新数据表预览
    this.updateTables(this.selectedTables, 'setting')
  }

  /**
   * 数据库更新数据表预览信息, 根据选择的 tables
   * 两个来源：
   *  1.选择表 - select
   *  2.修改脱敏配置 - 'setting' （不需要更新所有表的表头信息 getTablesHead ）
   */
  public async updateTables(tables: any, form: string) {
    if (tables.length === 0) {
      return
    }
    if (tables && tables.length > 0) {
      let tableName = tables[tables.length - 1] as string
      // 修改配置
      if (
        form === 'setting' &&
        !!this.activeTable &&
        tables.includes(this.activeTable)
      ) {
        tableName = this.activeTable
      }
      // 设置激活的表格,因为用了v-if 所以必须放到下一轮微任务来激活对应表格，否则$refs引用不到
      this.$nextTick(() => {
        this.activeTable = tableName
      })
      try {
        const result = await this.changeTablePreviewData(tableName)
        if (result && result.data.length === 0) {
          this.$message.warn('该数据表为空！')
        }
      } catch (error) {
        console.log('getTableData error:', error)
      }
    }
    if (form === 'select') {
      await this.getTablesHead(tables)
    }
    // data upload success, user guide to the next step
    UserGuideStore.toSpecifiedGuideStep(4)
  }

  /**
   * 根据用户选择请求数据进行预览
   * 唯一一个数据库数据预览的接口获取
   */
  public async changeTablePreviewData(table: string) {
    // 修改当前选中的 table，并改变遮罩状态
    this.updateTablePreviewState(table, true)
    const maskData: any = []
    // 有脱敏配置
    if (this.haveSetDesensitization[table]) {
      const columnNames = Object.keys(this.haveSetDesensitization[table])
      columnNames.forEach((item) => {
        maskData.push({
          dataLevelId: this.haveSetDesensitization[table][item].masking
            ? this.haveSetDesensitization[table][item].dataLevelId
            : null,
          dataMaskingType: this.haveSetDesensitization[table][item].masking
            ? this.haveSetDesensitization[table][item].dataMaskingType
            : null,
          importColumn: this.haveSetDesensitization[table][item].importColumn,
          masking: this.haveSetDesensitization[table][item].masking,
          name: item,
          semantic:
            this.databaseHeadSemantic[table][item]?.semantic ||
            this.databaseHeadSemantic[table][item]?.recommendSemantic ||
            'null',
          type: this.databaseHeadSemantic[table][item].type,
        })
      })
    }
    let passData = {
      ...DataUploadStore.databaseConfig,
      tableName: table,
    }

    if (maskData.length !== 0) {
      passData = {
        ...passData,
        baseTableConfigVO: {
          data: maskData,
        },
      }
    }
    let returnResult: any = null // 预览数据
    try {
      returnResult = await DataUploadStore.getTablePreviewData(passData)
      this.updateTablePreviewState(table, false)
      // 设置激活的表格,因为用了v-if 所以必须放到下一轮微任务来激活对应表格，否则$refs引用不到
      this.$nextTick(() => {
        this.updateActiveTableAndLoading(true, table)
      })
    } catch (error) {
      this.updateActiveTableAndLoading(false)
      console.error('getTableData error:', error)
      this.$message.error('获取表格数据失败，请刷新重试')
      this.updateTablePreviewState(table, false)
    }
    return returnResult
  }

  /**
   * 更新当前激活的表和 loading 状态（由父组件： DataUploadPage 调用）
   * @param loading
   * @param table
   */
  public updateActiveTableAndLoading(loading: boolean, table?: any) {
    this.loadSuccessed = loading
    if (table) {
      this.activeTable = table
    }
  }

  /**
   * 更新数据表相关信息
   */
  public updateTablePreviewState(tableName: string, state: boolean) {
    this.selectedPreviewTableName = tableName
    if (!state) {
      // tab切换后数据加载ready
      const { head } = this.selectedTableData
      const targetSemantic = this.databaseHeadSemantic[tableName] // 推断的语义
      if (targetSemantic) {
        head.forEach((column: any) => {
          // targetSemantic[column.name] 有可能为 undefined
          column.recommendSemantic =
            targetSemantic[column.name]?.recommendSemantic
          column.semantic = targetSemantic[column.name]?.semantic
        })
        DataUploadStore.setSelectedTableData({
          ...this.selectedTableData,
          head,
        })
      } else {
        console.error('targetSemantic error', targetSemantic)
      }
    }
  }

  /**
   * 脱敏组件修改 是否使用类型/语义推断
   * @param type 数据类型（数据库没有类型推断） / 数据语义
   * @param value 是否使用推断
   */
  public toggleTypeSemanticInfer({
    type,
    value,
  }: {
    type: 'type' | 'semantic'
    value: boolean
  }) {
    if (type === 'semantic') {
      // 表
      Object.keys(this.databaseHeadSemantic).forEach((tableName: string) => {
        const currentTable: any = this.databaseHeadSemantic[tableName]
        // 列
        Object.keys(currentTable).forEach((colName: string) => {
          const columnInfo: any = currentTable[colName]
          currentTable[colName].semantic =
            value && columnInfo.recommendSemantic
              ? columnInfo.recommendSemantic
              : 'null'
        })
        // 当修改的是当前选择的预览表
        if (this.selectedTableData.name === tableName) {
          this.changeCurrentPreviewTableSemantic(tableName)
        }
      })
    }
  }

  /**
   * 当修改的是当前选择的预览表
   */
  public changeCurrentPreviewTableSemantic(tableName: string) {
    const currentTable: any = this.databaseHeadSemantic[tableName]
    const { head } = this.selectedTableData
    head.forEach((item: any) => {
      item.semantic = currentTable[item.name].semantic
    })
    DataUploadStore.setSelectedTableData({
      ...this.selectedTableData,
      head,
    })
  }

  /**
   * 单个的修改修改语义
   */
  public onChangeSemantic({
    colName,
    semantic,
  }: {
    tableName: string
    colName: string
    semantic: string
  }) {
    const { activeTable } = this // 当前激活预览的表
    const data = this.databaseHeadSemantic[activeTable] || {}
    data[colName].semantic = semantic
    this.databaseHeadSemantic[activeTable] = data
    // 当修改的是当前选择的预览表
    if (this.selectedTableData.name === activeTable) {
      const { head } = this.selectedTableData
      const index = head.findIndex((c: any) => c.name === colName)
      head.splice(index, 1, {
        ...head[index],
        semantic,
      })
      DataUploadStore.setSelectedTableData({
        ...this.selectedTableData,
        head,
      })
    }
  }

  public reloadData() {}
}
</script>
<style lang="less" scoped>
.database-data-preview-card {
  //max-height: 492px;

  .reload {
    color: #5561ff;
    cursor: pointer;
  }

  &::-webkit-scrollbar {
    height: 6px;
    width: 6px;
  }

  &::-webkit-scrollbar-thumb {
    background: rgba(144, 147, 153, 0.5);
    border-radius: 6px;
  }

  &::-webkit-scrollbar-track {
    background: transparent;
    border-radius: 5px;
  }
}
</style>
